﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Warensoft.Unity.Communication.Client.Models;
using System.Data;
using System.IO;

namespace Warensoft.Unity.Communication.Client.DataClient
{
    public class DataEntitySet
    {
        public string TableName
        {
            get
            {
                return this.schemaTable.TableName;
            }
        }
        public IEnumerable <DataEntity> Entities
        {
            get
            {
                return this.list.Where(entity=>entity.State !=  EntityState.Deleted );
            }
        }
        internal IEnumerable<DataEntity> ChangedEntities
        {
            get
            {
                return this.list.Where(entity=>entity.State != EntityState.Unchanged);
            }
        }
        private bool isNavigationTable = false;
        private DataContext currentContext;

        private List<DataEntity> list = new List<DataEntity>();
        DataTable schemaTable;
        public DataEntitySet(DataContext context,DataTable schemaTable,bool isNavigationTable=false)
        {
            this.schemaTable = schemaTable;
            this.currentContext = context;
            this.isNavigationTable = isNavigationTable;

        }
        protected void LoadAsync(Action fillAsyncCompleted, string commandText,Dictionary<string,object>parameters)
        {
            DataServicePackage package = new DataServicePackage();
            package.Command = "CreateDataSet";
            package.CommandText =commandText ;
            //package.Parameters = parameters;
            this.currentContext.SendMessage(package, (result) => 
            {
                
                MerageTable(result);
                //this.AcceptChanges();
                fillAsyncCompleted();
            });
        }

        

        private void MerageTable(DataServicePackage result)
        {
            List<string> keyColumns = this.schemaTable.PrimaryKey.Select(col => col.ColumnName).ToList();
            foreach (DataRow row in (result.Result.AdditionalData as DataSet).Tables[0].Rows)
            {
                var entities = this.list.Where(entity =>
                {
                    List<bool> containsList = new List<bool>();
                    foreach (var key in keyColumns)
                    {
                        if (entity.Properties[key].OriginalValue.Equals(row[key]))
                        {
                            containsList.Add(true);
                        }
                    }
                    if (containsList.Count == 0)
                    {
                        return false;
                    }
                    var contains = containsList[0];
                    foreach (var item in containsList)
                    {
                        contains = (contains && item);
                    }
                    return contains;
                }).ToList();
                if (entities.Count() == 0)
                {
                    row.Table.TableName = this.schemaTable.TableName;
                    this.Add(new DataEntity(row, this.currentContext));
                }
                else
                {
                    var entity = entities.First();
                    foreach (var property in entity.Properties)
                    {
                        property.Value = row[property.ColumnName];
                    }
                }
                //this.Add(new DataEntity (row,this.currentContext ));
            }
        }
        public void LoadAsync(Action fillAsyncCompleted, DataQuery query)
        {
            //this.LoadAsync(fillAsyncCompleted, string.Format("select * from [{0}] {1}", this.TableName,query.ToString ()),query.Parameters);
            DataServicePackage package = new DataServicePackage();
            package.Command = "GetData";
            //package.CommandText = this.TableName ;
            package.CommandText = this.TableName;
            package.Result = new ResultInfo() 
            {
                AdditionalData =query .ToArray ()
            };
            this.currentContext.SendMessage(package, (result) =>
            {

                MerageTable(result);
                //this.AcceptChanges();
                fillAsyncCompleted();
            });
        }
        public void LoadAsync(Action fillAsyncCompleted)
        {
            this.LoadAsync(fillAsyncCompleted,new DataQuery ());
            
        }
        public void Add(DataEntity item)
        {
            if (item.TableName !=this.TableName )
            {
                throw new Exception("新添加的实体必须与该实体集具备相同的架构");
            }
            this.list.Add(item);
            
        }

        public void Clear()
        {
            this.list.Clear();
        }

        public bool Contains(DataEntity item)
        {
            return this.list.Contains(item);
        }

        public void CopyTo(DataEntity[] array, int arrayIndex)
        {
            array=this.list.Skip(arrayIndex).ToArray();
        }

        public int Count
        {
            get { return this.list.Count; }
        }

        

        public bool Remove(DataEntity item)
        {
            return this.list.Remove(item);
        }

        public IEnumerator<DataEntity> GetEnumerator()
        {
            return this.list.GetEnumerator();
        }
#if !SERVER
        public DataEntity NewEntity()
        {
            var newrow = this.schemaTable .NewRow();
            DataEntity entity = new DataEntity(newrow, this.currentContext);
            entity.isNew = true;
            entity.state = EntityState.Added;
            return entity;
        }
#endif
        public void AcceptChanges(Guid packageID)
        {
            var deletedEnties = this.list.Where(e => e.state == EntityState.Deleted&&e.UpdateStub ==packageID).ToArray();
            
            for (int i = 0; i < deletedEnties.Length; i++)
            {
                this.list.Remove(deletedEnties[i]);
            }
            var entities = this.list.Where(e=>e.UpdateStub ==packageID );
            foreach (var item in entities)
            {
                item.AcceptChanges();
            }
        }
        public void AcceptChanges()
        {
            var deletedEnties = this.list.Where(e=>e.state == EntityState.Deleted).ToArray ();
            for (int i = 0; i < deletedEnties.Length ; i++)
            {
                this.list.Remove(deletedEnties[i]);
            }
            foreach (var item in this.list )
            {
                item.AcceptChanges();
            }
        }
    }
}
